#define _POSIX_SOURCE
#define _BSD_SOURCE

#include "dominion.h"
#include "dominion_helpers.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include "rngs.h"

#ifndef MAX_PLAYER
#define MAX_PLAYER 4
#endif

#ifndef MAX_COIN
#define MAX_COIN 8
#endif

#ifndef MAX_SUPP
#define MAX_SUPP 13
#endif

#ifndef SAMPLE_BUY
#define SAMPLE_BUY 3
#endif

int checkBuyCard(int expected, int supplyPos, struct gameState *post)
{
	struct gameState pre;
	int result;

	/* Copy memory located at post to memory located at pre */
	memcpy(&pre, post, sizeof(struct gameState));

	result = buyCard(supplyPos, post);
	assert(result == expected);
	
	if (result == 0) {
		pre.discard[pre.whoseTurn][pre.discardCount[pre.whoseTurn]] = supplyPos;
		pre.discardCount[pre.whoseTurn]++;
		pre.supplyCount[supplyPos]--;
		pre.coins -= getCost(supplyPos);
		pre.numBuys--;
		pre.phase = 1; // Author comments that he doesn't know what to do about this.
	
		assert(post->discard[post->whoseTurn][post->discardCount[post->whoseTurn] - 1] == supplyPos);
		assert(pre.discard[pre.whoseTurn][pre.discardCount[pre.whoseTurn] - 1] == supplyPos);
	}
	assert(memcmp(&pre, post, sizeof(struct gameState)) == 0);

	return 0;
}

void sigabrt_catch(int sig)
{
	printf("SIGABRT has been caught\n");
	exit(0);
}

int main(int argc, char **argv)
{
	int i, n, expected, supplyPos;

	int k[10] = {adventurer, council_room, feast, gardens, mine,
			remodel, smithy, village, baron, great_hall};

	struct gameState G;

	signal(SIGABRT, sigabrt_catch);

	printf("Testing buyCard.\n");

	printf("RANDOM TESTS.\n");

	/* Set Random Number Generator */
	SelectStream(2);
	PutSeed(3);

	for (n = 1; n <= 20000; n++) {
		for (i = 0; i < sizeof(struct gameState); i++) {
			((char *) &G)[i] = floor(Random() * 256);
		}
		supplyPos = k[(int) floor(Random() * 10)];

		/* Randomly Set Game Numbers */ 
		G.whoseTurn = floor(Random() * MAX_PLAYER);;
		G.numBuys = floor(Random() * SAMPLE_BUY);
		G.coins = floor(Random() * (MAX_COIN +1));
		G.deckCount[G.whoseTurn] = floor(Random() * MAX_DECK);
		G.discardCount[G.whoseTurn] = floor(Random() * MAX_DECK);
		G.handCount[G.whoseTurn] = floor(Random() * MAX_HAND);
		for (i = 0; i < 10; i++) {
			G.supplyCount[k[i]] = floor(Random() * MAX_SUPP);
		}

		if (argc > 1 && strcmp(argv[1], "-v") == 0) {
			printf("Test #%5d: player = %d supplyPos = %2d, buys=%d, cost=%d, coins=%d\n", 
					n, G.whoseTurn, supplyPos, G.numBuys, getCost(supplyPos), G.coins);
		}
		
		if (G.supplyCount[supplyPos] == 0 || G.numBuys == 0 || G.coins < getCost(supplyPos)) {
			expected = -1;
		} else {
			expected = 0;
		}
		
		checkBuyCard(expected, supplyPos, &G);
	}

	printf ("ALL TESTS OK\n");

	return 0;
}